﻿using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ProtoBuf;

namespace KC.Common
{
    /// <summary>
    /// 提供了一个关于对象序列化的辅助类
    /// </summary>
    public static class SerializeHelper
    {
        #region Newtonsoft.Json序列化

        /// <summary>
        /// 类对像转换成json格式
        /// </summary>
        /// <param name="t"></param>
        /// <param name="hasNullIgnore">是否忽略NULL值</param>
        /// <param name="hasLoopIgnore">是否忽略循环引用</param>
        /// <returns></returns>
        public static string ToJson<T>(T t, bool hasNullIgnore = false, bool hasLoopIgnore = false)
        {
            if (hasNullIgnore && hasLoopIgnore)
            {
                return JsonConvert.SerializeObject(t, Formatting.Indented,
                    new JsonSerializerSettings
                    {
                        NullValueHandling = NullValueHandling.Ignore,
                        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                    });
            }
            else if (hasLoopIgnore)
                return JsonConvert.SerializeObject(t,
                    new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
            else if (hasNullIgnore)
                return JsonConvert.SerializeObject(t,
                    new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
            else
                return JsonConvert.SerializeObject(t);
        }

        /// <summary>
        /// json格式转换
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="strJson"></param>
        /// <returns></returns>
        public static T FromJson<T>(string strJson) 
        {
            
            if (!string.IsNullOrEmpty(strJson))
                return JsonConvert.DeserializeObject<T>(strJson);
            return default(T);
        }

        /// <summary>
        /// 从json字符串中获取某字段的值
        /// </summary>
        /// <param name="strJson"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetValueFromJson(string strJson, object key)
        {
            if (!string.IsNullOrEmpty(strJson) && key != null)
            {
                JObject obj = JObject.Parse(strJson);
                JToken value = obj[key];
                return value.ToString();
            }
            return string.Empty;
        }

        #endregion

        #region Protobuf.Net序列化
        /// <summary>
        /// Protobuf.Net序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static byte[] ToProtobufBinary<T>(T obj)
        {
            if (obj == null)
            {
                return null;
            }

            using (var ms = new MemoryStream())
            {
                Serializer.Serialize(ms, obj);
                return ms.ToArray();
            }
        }
        /// <summary>
        /// Protobuf.Net反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static T FromProtobufBinary<T>(byte[] stream)
        {
            if (stream == null)
            {
                return default(T);
            }

            using (var ms = new MemoryStream(stream))
            {
                T t = Serializer.Deserialize<T>(ms);
                return t;
            } 
        }

        public static object FromProtobufBinary(Type type, byte[] stream)
        {
            if (stream == null)
            {
                return null;
            }

            using (var ms = new MemoryStream(stream))
            {
                return Serializer.NonGeneric.Deserialize(type, ms);
            }
        }
        #endregion

        #region BinaryFormatter序列化

        public static byte[] ToBinary<T>(T obj)
        {
            if (obj == null)
            {
                return null;
            }

            var binaryFormatter = new BinaryFormatter();
            using (var memoryStream = new MemoryStream())
            {
                binaryFormatter.Serialize(memoryStream, obj);
                byte[] objectDataAsStream = memoryStream.ToArray();
                return objectDataAsStream;
            }
        }

        public static T FromBinary<T>(byte[] stream)
        {
            if (stream == null)
            {
                return default(T);
            }

            var binaryFormatter = new BinaryFormatter();
            using (var memoryStream = new MemoryStream(stream))
            {
                T result = (T)binaryFormatter.Deserialize(memoryStream);
                return result;
            }
        }
        #endregion
    }
}
